use crate::board::Board;
use crate::board::Dir;
use crate::board::Pos;
use crate::color::Color;
use crate::piece::PieceType;
use std::convert::TryInto;
use std::mem::transmute;

#[derive(Clone, Copy, PartialEq, Eq)]
pub struct Move {
    from: Pos,
    to: Pos,
}

impl Move {
    pub fn new(from: Pos, to: Pos) -> Move {
        debug_assert!(from != to);
        Move { from, to }
    }

    #[inline]
    pub fn from(self) -> Pos {
        self.from
    }

    #[inline]
    pub fn to(self) -> Pos {
        self.to
    }

    pub fn as_u16(self) -> u16 {
        let x: u16 = unsafe { transmute(self) };
        x
    }

    pub fn human_string(self, board: &Board) -> String {
        let piece = board[self.from];
        if piece.is_none() {
            panic!("走法跟棋盘不对应");
        }
        let piece = piece.unwrap();
        let piece_string = piece.piece_type().human_string(piece.color());
        // 目标位置在原位置的什么方向
        let direction = if self.to.row() < self.from.row() {
            "UP"
        } else if self.to.row() == self.from.row() {
            "SAME"
        } else {
            "DOWN"
        };
        let dir_string = if direction == "SAME" {
            "平"
        } else {
            let color_red = piece.color() == Color::RED;
            let dir_up = direction == "UP";
            if dir_up == color_red {
                "进"
            } else {
                "退"
            }
        };
        // 查看同一列是不是有跟要走动的棋子相同的棋子
        let mut from_column_pos = self.from;
        while from_column_pos.relative(Dir::Down).is_some() {
            from_column_pos = from_column_pos.relative(Dir::Down).unwrap();
        }
        let mut same_column_piece_count = 0usize;
        let mut the_piece_index = 0usize;
        loop {
            if board[from_column_pos] == Some(piece) {
                if from_column_pos == self.from {
                    the_piece_index = same_column_piece_count;
                }
                same_column_piece_count += 1;
            }
            let up_pos = from_column_pos.relative(Dir::Up);
            if up_pos.is_none() {
                break;
            }
            from_column_pos = up_pos.unwrap();
        }
        static NUM: [[&'static str; 9]; 2] = [
            ["1", "2", "3", "4", "5", "6", "7", "8", "9"],
            [
                "九", "八", "七", "六", "五", "四", "三", "二", "一",
            ],
        ];
        let mut string = "".to_string();
        if same_column_piece_count == 0 {
            panic!("相同的棋子不可能一个都找不到，因为自身也算在其中");
        } else if same_column_piece_count == 1 {
            // 唯一的棋子
            string += &piece_string;
            string += NUM[piece.color().color_index()][self.from.column()];
        } else if piece.piece_type() != PieceType::PAWN {
            if same_column_piece_count != 2 {
                panic!("兵卒以外的棋子数量过多");
            }
            // 有两个棋子，用相对方向区分（对于士和象，其实没有必要用前后区分，这里为了一致性还是用前后区分）
            let rel_dir_string = {
                let color_red = piece.color() == Color::RED;
                let index_zero = the_piece_index == 0;
                if color_red == index_zero {
                    "后"
                } else {
                    "前"
                }
            };
            string += rel_dir_string;
            string += &piece_string;
        } else {
            if same_column_piece_count > 5 {
                panic!("相同棋子数量过多");
            }
            if piece.piece_type() != PieceType::PAWN {
                panic!("兵卒以外的棋子数量过多");
            }
            let rel_dir_string = {
                if same_column_piece_count == 3 && the_piece_index == 1 {
                    "中"
                } else if piece.color() == Color::RED {
                    if the_piece_index == same_column_piece_count - 1 {
                        "前"
                    } else if same_column_piece_count == 2
                        || (same_column_piece_count == 3 && the_piece_index == 0)
                    {
                        "后"
                    } else {
                        NUM[piece.color().color_index()]
                            [8 - (same_column_piece_count - the_piece_index - 1)]
                    }
                } else {
                    if the_piece_index == 0 {
                        "前"
                    } else if same_column_piece_count == 2
                        || (same_column_piece_count == 3
                            && the_piece_index == same_column_piece_count - 1)
                    {
                        "后"
                    } else {
                        NUM[piece.color().color_index()][the_piece_index]
                    }
                }
            };
            string += rel_dir_string;
            string += &piece_string;
            // 查找是不是有别的路也存在有多个兵卒的情况
            // 如果有两路都有多个兵卒，需要增加更多信息来区分
            let mut p = self.from;
            let mut has_other = false;
            loop {
                let p_right = p.relative(Dir::Right);
                if p_right.is_some() {
                    p = p_right.unwrap();
                } else {
                    break;
                }
            }
            loop {
                loop {
                    let p_down = p.relative(Dir::Down);
                    if p_down.is_some() {
                        p = p_down.unwrap();
                    } else {
                        break;
                    }
                }
                let mut count = 0;
                let mut same_column = false;
                let mut no_pos_left = false;
                loop {
                    if p == self.from {
                        same_column = true;
                    }
                    if board[p] == Some(piece) {
                        count += 1;
                    }
                    let p_up = p.relative(Dir::Up);
                    if p_up.is_some() {
                        p = p_up.unwrap();
                    } else {
                        let p_left = p.relative(Dir::Left);
                        if p_left.is_some() {
                            p = p_left.unwrap();
                        } else {
                            no_pos_left = true;
                        }
                        break;
                    }
                }
                if count >= 2 && !same_column {
                    has_other = true;
                    break;
                }
                if no_pos_left {
                    break;
                }
            }
            if has_other {
                // 有别的路也有多个兵卒的情况，加上额外信息
                string += NUM[piece.color().color_index()][self.from.column()];
                // 其实即使有别的路有多个兵卒，也不一定需要额外信息，因为别的兵卒的名称可能不同（比如如果兵卒的数量不超过5，
                // 不会有两路都有中兵），别的路的兵卒也许不能按规则走到目标路等，这里先无视这些情况，因为本来也找不到权威的规定
            }
        }
        string += dir_string;
        if direction == "SAME"
            || [PieceType::GUARD, PieceType::MINISTER, PieceType::KNIGHT]
                .contains(&piece.piece_type())
        {
            string += NUM[piece.color().color_index()][self.to.column()];
        } else {
            let from_row: i32 = self.from.row().try_into().unwrap();
            let to_row: i32 = self.to.row().try_into().unwrap();
            let diff_abs: i32 = (from_row - to_row).abs();
            string += NUM[piece.color().color_index()][if piece.color() == Color::BLACK {
                let index: usize = diff_abs.try_into().unwrap();
                index - 1
            } else {
                let index: usize = diff_abs.try_into().unwrap();
                8 - (index - 1)
            }]
        }
        string
    }
}
